#include "opencv2/core/core.hpp"        // Basic OpenCV structures (cv::Mat, Scalar)
#include "opencv2/imgproc/imgproc.hpp"  // Gaussian Blur
//#include "opencv2/videoio/videoio.hpp"
#include "opencv2/highgui/highgui.hpp"  // OpenCV window I/O

#include <iostream> // for standard I/O
#include <string>   // for strings
#include <iomanip>  // for controlling float print precision
#include <sstream>  // string to number conversion
#include <algorithm>

//! Specific includes for pure c++ directory creation
#if (_WIN32)
	#include <direct.h>
  #include <windows.h>
#else
  #include <dirent.h>
#endif

#include "contourfinder.hpp"
 
#define DATA_DIR "C:/Users/patis/Documents/Projects/git_personal/opencvtests/data/2015-02-07/"
#define FILE_EXT "png"

int main(int argc, char** argv) 
{
  std::string data_dir = argv[2];
  std::string output_dir = data_dir + std::string("//output//");
  //! Pure c++ based directory creation
#if defined(_WIN32)
  DWORD ftyp = GetFileAttributesA( output_dir.c_str() ); // check if directory exists or not
  if (ftyp == INVALID_FILE_ATTRIBUTES)
	  _mkdir(output_dir.c_str());
#else
  DIR *pDir;
  pDir = opendir(output_dir.c_str()) // check if directory exists or not
  if (pDir == NULL)
	  mkdir(output_dir.c_str(), 0777);
#endif
	
  cv::Mat input_image;
	std::string cluster_output = "cluster_output", gaussian_output = "gaussian_output",
    input_file = ".png", file_to_read;

  //img = cv::imread(/*argv[1]*/input_file, cv::IMREAD_GRAYSCALE);
  //img = cv::imread(argv[1]), cv::IMREAD_GRAYSCALE);
  //cv::VideoCapture sequence( DATA_DIR + std::string("%1d.png") );
  
  //int i = 0;
  for(int i=1; i<10; i++)
  {
    //i++;
    std::string i_string = std::to_string(i);
    //sequence >> img;
    file_to_read = data_dir + std::string("/") + i_string + input_file;
    input_image = cv::imread(file_to_read, cv::IMREAD_GRAYSCALE);

	  //cv::cvtColor(img, img, cv::COLOR_BGR2GRAY);
 
    const int origRows = input_image.rows;
    cv::Mat colVec = input_image.reshape(1, input_image.rows*input_image.cols); // change to a Nx3 column vector
    cv::Mat colVecD, bestLabels, centers, clustered;
    int attempts = 5;
    int clusts = 2;
    double eps = 0.001;
    colVec.convertTo(colVecD, CV_32FC3, 1.0/255.0); // convert to floating point
 
    std::cerr << "Starting K-means now..\n";
    double compactness = cv::kmeans(colVecD, clusts, bestLabels, 
          cv::TermCriteria(cv::TermCriteria::EPS+cv::TermCriteria::COUNT, attempts, eps), 
          attempts, cv::KMEANS_PP_CENTERS, centers);
    std::cerr << "K-means over. \n";
    cv::Mat labelsImg = bestLabels.reshape(1, origRows); // single channel image of labels
    labelsImg.convertTo(labelsImg, input_image.depth());
    //cv::cvtColor(labelsImg, labelsImg, cv::COLOR_GRAY2BGR);
    //cout << "Compactness = " << compactness << endl;
    
    cv::Mat labels_normalized, gaussian_mat;
    cv::normalize(labelsImg, labels_normalized, 0, 255, cv::NORM_MINMAX, CV_8UC1);

    std::vector<cv::Point> black_pixels, white_pixels;
    cv::findNonZero(labels_normalized, black_pixels);

    int number_of_black_pixels = black_pixels.size(), 
      number_of_white_pixels = colVec.rows - number_of_black_pixels;
    if( number_of_white_pixels < number_of_black_pixels )
      cv::bitwise_not(labels_normalized, labels_normalized);

    std::string cluster_output_file = output_dir + i_string + cluster_output + std::string(".") + FILE_EXT;
    cv::imwrite(std::string(cluster_output_file), labels_normalized);
	  std::cerr << "K means output written to file. \n\n";

	  const int gauss_sigma = 15;
    std::cerr << "Starting Gaussian blur.\n";
	  cv::GaussianBlur( labels_normalized, gaussian_mat, cv::Size(gauss_sigma, gauss_sigma), 0, 0);
	  cv::threshold(gaussian_mat, gaussian_mat, 5, 255, cv::THRESH_BINARY);
    std::cerr << "Gaussian blur over.\n";
    std::string gaussian_output_file = output_dir + i_string + gaussian_output + std::string(".") + FILE_EXT;
	  cv::imwrite(std::string(gaussian_output_file), gaussian_mat);
    std::cerr << "Gaussian output written to file.\n\n";
    //cv::namedWindow(cluster_output, cv::WINDOW_NORMAL);
    //cv::imshow(cluster_output, labels_normalized);
	  //cv::waitKey();
  }
     
  return EXIT_SUCCESS;
}
